<?xml version="1.0" encoding="UTF-8"?>
<doc>
<title>异常处理</title>

<para>
<ptitle>异常处理</ptitle>
　<kw>异常</kw>是指正常情况下不会发生的所谓「例外」的情况。在大部分情况下异常和错误可以当作同义词。<r/>
</para>

<para>
<ptitle>异常会发生的地方</ptitle>
　程序的任何地方都有发生异常的可能性。<r/>
　发生异常的时候，异常将被「投出(throw)」。<r/>
　比如说，以下的脚本将会引起错误。<r/>
<r/>
<example>
	"3%0"!; // 发生“除以0错误”的异常
</example>
<r/>
　虽然有像上例一样明显会发生异常的情况，但也有一些情况下，无法知道代码是否一定会发生异常。<r/>
</para>

<para>
<ptitle>异常的捕捉</ptitle>
　使用 <tt><kw>try</kw></tt> (尝试) 关键字和 <tt><kw>catch</kw></tt> (捕捉) 关键字，可以捕捉异常。<r/>
　例如说，为了捕捉上面所说的“不知道是否会发生的异常”，可以象下面这样编写代码。<r/>
<r/>
<example>
	try // 不知道是否会发生异常<r/>
	{<r/>
		func1(); // 这里有可能会发生异常<r/>
	}<r/>
	catch // 捕捉异常<r/>
	{<r/>
		// 当发生异常的时候，这里的代码被执行<r/>
		inform("无法读取图像。"); // 显示信息<r/>
	}<r/>
</example>
<r/>
　像这样在 try 代码段中编写可能会发生异常的代码，就可以在发生异常的时候执行 catch 代码段中的代码。利用这个功能，可以编写出清晰流畅的错误处理代码。<r/>
<r/>
　在 try 代码段中没有发生任何异常的情况下，catch 代码段不会被执行。<r/>
<r/>
　try 代码段中可以编写任何的代码。除了在代码段中直接发生异常的情况之外，在代码段中调用的函数，以及被函数调用的函数中发生的异常，try ... catch 代码都可以捕捉到。<r/>
<r/>
　发生异常的情况下，代码段剩下的执行步骤将被中断，并返回到 try 语句的位置。<r/>
<r/>
　如果在 catch 代码段中也发生了异常，该异常便无法在这个 catch 代码段中被捕捉。这个异常将会按照调用上下文向上回溯，如果在发生错误的 catch 代码上层存在 try 语句，则异常将在那里被捕捉。<r/>
<r/>
　在异常被抛出之后，程序到达 catch 块之前有发生其他异常的可能性，但这种情况下的操作未被定义。<r/>
<r/>
　如果异常在脚本中完全没有被捕捉到，则异常将离开脚本而被传递给应用程序，由应用程序来进行处理。<r/>
<note>
一般来说，由于错误而被抛出的异常会中断脚本的执行，所以建议尽可能在可能发生错误的地方写入 try ... catch 。</note>
</para>

<para>
<ptitle>异常对象</ptitle>
　关于异常的各种各样的欣喜，都会和一个 <kw>Exception</kw> 类的对象一起被投出。这个对象被称做异常对象，可以通过 catch 语句来获取。<r/>
　例如说，我们可以编写以下代码。<r/>
<example>
	try<r/>
	{<r/>
		loadImages("nothing.jpeg"); // 可能会发生异常的操作<r/>
	}<r/>
	catch (e) // 利用 e 这个变量获取异常对象<r/>
	{<r/>
		// e.message 是和异常一起投出的消息字符串。<r/>
		// 一些情况下发生异常的理由会通过这个变量说明。<r/>
		inform("无法读取图像。\n"+e.message);<r/>
	}<r/>
</example>
　像这样，在 catch 后的括号中写入变量名，就可以利用这个变量接收异常对象。<r/>
　这个变量的作用域，从 catch 后的代码段中开始，并随着程序离开这个代码段而结束。此外，这个变量不需要事先的声明。<r/>
</para>

<para>
<ptitle>throw 语句</ptitle>
　在 TJS 程序中可以使用 <tt><kw>throw</kw></tt> 关键字投出异常。<r/>
　例如，我们可以编写如下代码。<r/>
<example>
	function pow2(n)<r/>
	{<r/>
		// 计算 2 的 n 次幂，提供的 n 必须是正整数<r/>
		if(n&lt;0) throw new Exception("不能指定负数。");<r/>
			// ↑ 发生异常<r/>
		return 1&lt;&lt;n;<r/>
	}<r/>
</example>
　如果给这个函数传递了类似于 -1 这样的负数，就会发生异常。投出异常可以使用类似以下的语句。<r/>
<r/>
<bq>
throw new Exception("不能指定负数。");
</bq>
<r/>
　<tt>new Exception("不能指定负数。")</tt> 这个语句将以字符串作为参数创建一个新的 Exception 类对象（详细请参考 Exception 类的说明）。然后将这个新创建的对象通过 throw 关键字投出。<r/>
　throw 关键字能投出的对象并非一定要是 Exception 类的对象，数字也好，字符串也好，包括对函数的引用也能够被投出。但是，我们推荐投出 Exception 类，或者这个类的派生类的对象。这样，在 catch 代码段中只需要统一编写对应 Exception 类对象的代码即可。<r/>
</para>

<para>
<ptitle>再次投出异常</ptitle>
　catch 可以捕捉到发生的异常，但在直接对应的 try 块的上层也有可能声明了别的 try 语句。在这种情况下，可以再次投出异常。<r/>
　我们可以编写如下代码。<r/>
<example>
	function tryloadimage()<r/>
	{<r/>
		try<r/>
		{<r/>
			primaryLayer.loadImages("test1.bmp"); // 尝试读取test1.bmp<r/>
		}<r/>
		catch(e)<r/>
		{<r/>
			inform("图像读取失败。");<r/>
			throw e; // 上面的信息被显示的同时，异常会被再次投出<r/>
		}<r/>
	}<r/>
<r/>
	function test()<r/>
	{<r/>
		// 调用 tryloadimage ，如果读取图像成功则返回 true<r/>
		// 否则返回 false 的函数<r/>
		try<r/>
		{<r/>
			tryloadimage();<r/>
		}<r/>
		catch<r/>
		{<r/>
			return false;<r/>
		}<r/>
		return true;<r/>
	}<r/>
</example>
　在这种情况下调用 test() ，并且图像读取失败，那么在 inform 方法显示出消息的同时，由于异常被再次投出，可以通过 test 函数内的 catch 代码进行捕捉。<r/>
</para>
</doc>